'''
Created on Feb 9, 2012

@author: xzhu
'''
import allState, ioniState
import stateHead

class hPath():
    '''
    classdocs
    '''

    def __init__(self):
        '''
        Constructor
        '''
        self.states = []

        
        # set the initial state of proton transfer step
        
        self.hist   = []
        
        # if history is empty
        if not self.hist:
            for i in range(stateHead.stateHead.n_res - 1):
                self.hist.append(0)
            self.hist.append(1)
        
        # suppose there are 6 residues, the initial value of hist is [0, 0, 0, 0, 0, 1], if we assume proton transfer
        #      is from left to right.
        # "0" means that the residue at that position is still be able to pass a proton to the next residue.
        # while "1" means that residue can't.
        
        
        self.highEner = -1000000.0
        
    def is_done(self):
        '''
        test if there is still a next path
        if there is any "0" in "hist", meaning there is still residue not giving a proton to its next residue
            then the whole proton transfer process isn't finished
        '''
        done = True
        for h in self.hist:
            if h == 0:
                done = False
                break
            
        return done    
        
    def get_first_state(self, samp_state):
        '''
        get the first state of this path, now history is empty
        '''
        
        self.states.append(samp_state)
        self.highEner = samp_state.ener
    
    def high_ener_states(self):
        '''
        Get the highest energy among all the intermediates in a path
        '''
        
        self.highEner = self.states[0].ener
        for state in self.states:
            if state.ener > self.highEner:
                self.highEner = state.ener
                    
    def copy_path(self, states, hist):
        '''
        get a new path from all the states
        '''
        
        self.states = list(states)
        self.hist = hist
        self.high_ener_states()
        
    def next_step(self, allstates):
        '''
        get the next step of pathway
        '''
        
        all_new_path = []
        
        
        for i in range(stateHead.stateHead.n_res - 1):
            if self.hist[i] == 0:
                
                # if it's possible to lose a proton (charge decrement by 1) at position "i" in the recently appended state
                if ((self.states[-1].crgs[i] - 1) in stateHead.stateHead.poss_ioni[i]):
                    # if it's possible to gain a proton (charge increment by 1) at position "i+1" (next position) in the recently appended state
                    if ((self.states[-1].crgs[i+1] + 1) in stateHead.stateHead.poss_ioni[i+1]):
                        # Now it's possible to pass a proton from position i to i+1, we generate a new state from it
                        new_crg = list(self.states[-1].crgs)
                        new_crg[i] = self.states[-1].crgs[i] - 1
                        new_crg[i+1] = self.states[-1].crgs[i+1] + 1
                        
                        new_hist = list(self.hist)
                        new_hist[i] += 1
                        #print len(allstates.states)
                        
                        # get this new state from all possible states loaded by charges on residues
                        new_state = allstates.state_of_crg(new_crg)
                        
                        #print new_state.crgs
                        
                        # add this new state to the states already exist
                        buff_states = list(self.states)
                        buff_states.append(new_state)
                        
                        # get a new path from the states with the one just generated (might still be an incomplete path)
                        new_path = hPath()
                        #print new_path.__class__
                        new_path.copy_path(buff_states, new_hist)
                        all_new_path.append(new_path)
                        
        return all_new_path
        
       
    def display(self):
        self.states[0].display()
        #print '\t%.1f' % self.highEner
        self.states.pop(0)
        for state in self.states:
            state.display()
            print
        print            # add an empty line to seperate different path 
        print
        print
        
